
// ===============================================================================================================
// -*- C++ -*-
//
// CommLib.cpp - Commom code and definitions used everywhere.
//
// Copyright (c) 2011 Guilherme R. Lampert
// guilherme.ronaldo.lampert@gmail.com
//
// This code is licenced under the MIT license.
//
// This software is provided "as is" without express or implied
// warranties. You may freely copy and compile this source into
// applications you distribute provided that the copyright text
// above is included in the resulting source code.
//
// ===============================================================================================================

#include <CommLib.hpp>
#include <cstdarg>

#if defined (_WIN32)
#include <windows.h>
#endif // _WIN32

// Local buffers
static char findBase[FILENAME_MAX];
static char findPath[FILENAME_MAX];
static int findHandle = 0;

namespace CommLib {

int CalcFPS(void)
{
#if defined (_WIN32)

	static int ret = 0;
	static float fps = 0.0f;
	static float lastTime = 0.0f;
	float currentTime = static_cast<float>((GetTickCount() * 0.001f));

	fps++;

	if ((currentTime - lastTime) > 1.0f)
    {
		lastTime = currentTime;
		ret = static_cast<int>(fps);
		fps = 0.0f;
	}

	return (ret);

#else
#error Windows specific code !
#endif // _WIN32
}

float GetElapsedMilliseconds(void)
{
#if defined (_WIN32)

	// GetTickCount() is very fast and reasonably accurate. The down side however is that
	// if the system runs continuously for more than ~49 days the counter will reset to zero.
	static const DWORD baseTime = GetTickCount();
	return (static_cast<float>(GetTickCount() - baseTime));

#else
#error Windows specific code !
#endif // _WIN32
}

float GetElapsedSeconds(void)
{
	return (GetElapsedMilliseconds() * 0.001f);
}

void FileGetPath(const char * in, char * out)
{
	const char * s;
	s = in + strlen(in) - 1;

	while (s != in && *s != '/')
		s--;

	strncpy(out, in, s-in);
	out[s-in] = 0;
}

bool FileCompareAttributes(unsigned int found, unsigned int mustHave, unsigned int cantHave)
{
	if ((found & _A_RDONLY) && (cantHave & FILE_RDONLY))
		return false;
	if ((found & _A_HIDDEN) && (cantHave & FILE_HIDDEN))
		return false;
	if ((found & _A_SYSTEM) && (cantHave & FILE_SYSTEM))
		return false;
	if ((found & _A_SUBDIR) && (cantHave & FILE_SUBDIR))
		return false;
	if ((found & _A_ARCH) && (cantHave & FILE_ARCH))
		return false;

	if ((mustHave & FILE_RDONLY) && !(found & _A_RDONLY))
		return false;
	if ((mustHave & FILE_HIDDEN) && !(found & _A_HIDDEN))
		return false;
	if ((mustHave & FILE_SYSTEM) && !(found & _A_SYSTEM))
		return false;
	if ((mustHave & FILE_SUBDIR) && !(found & _A_SUBDIR))
		return false;
	if ((mustHave & FILE_ARCH) && !(found & _A_ARCH))
		return false;

	return true;
}

char * FileFindFirst(const char * path, unsigned int mustHave, unsigned int cantHave)
{
	struct _finddata_t findinfo;

	if (findHandle)
	{
		FileFindClose();
	}

	FileGetPath(path, findBase);

	findHandle = _findfirst(path, &findinfo);

	if (findHandle == -1)
	{
		return (0);
	}

	if (!FileCompareAttributes(findinfo.attrib, mustHave, cantHave))
	{
		return (0);
	}

	if (*findBase)
	{
		sprintf(findPath, "%s/%s", findBase, findinfo.name);
	}
	else
	{
		sprintf(findPath, "%s", findinfo.name);
	}

	return (findPath);
}

char * FileFindNext(unsigned int mustHave, unsigned int cantHave)
{
	struct _finddata_t findinfo;

	if (findHandle == -1)
	{
		return (0);
	}

	if (_findnext(findHandle, &findinfo) == -1)
	{
		return (0);
	}

	if (!FileCompareAttributes(findinfo.attrib, mustHave, cantHave))
	{
		return (0);
	}

	if (*findBase)
	{
		sprintf(findPath, "%s/%s", findBase, findinfo.name);
	}
	else
	{
		sprintf(findPath, "%s", findinfo.name);
	}

	return (findPath);
}

void FileFindClose(void)
{
	if (findHandle != -1)
	{
		_findclose(findHandle);
	}

	findHandle = 0;
}

#if defined (_DEBUG)
int verbosityLevel = VL_PRINT_ALL;
#else
int verbosityLevel = VL_PRINT_ERR;
#endif // _DEBUG

void DbgPrintf(int verbosity, const char * format, ...)
{
	const int TEMP_STRING_SIZE = 2048;
	char tempString[TEMP_STRING_SIZE];

	char * ptr;
	va_list vaList;
	int n;

	assert(format != 0 && "Null format string !");

	if (verbosityLevel >= verbosity)
	{
		switch (verbosity)
		{
		case PRINT_ERROR:
			strcpy(tempString, "ERROR: "); n = 7;
			ptr = (tempString + n);
			break;

		case PRINT_WARN:
			strcpy(tempString, "WARN: "); n = 6;
			ptr = (tempString + n);
			break;

		default:
			strcpy(tempString, "MSG: "); n = 5;
			ptr = (tempString + n);
			break;
		}

		va_start(vaList, format);
		n = vsnprintf(ptr, (TEMP_STRING_SIZE - n) - 1, format, vaList);
		va_end(vaList);

		if (n > 0)
		{
			// Break the line
			ptr[n] = '\n';
			ptr[n + 1] = 0;

			// Redirect to stdout
			fputs(tempString, stdout);

			#if defined (_WIN32)
			// And to the windows API debug output
			OutputDebugStringA(tempString);
			#endif // _WIN32
		}
	}
}

}; // namespace CommLib {}